const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';

class Promise {
    constructor(executor) {
        this.status = PENDING;
        this.value = undefined;  // 成功的数据
        this.reason = undefined; // 失败的数据
        this.onResolvedCallbacks = [];
        this.onRejectedCallbacks = [];

        const resolve = (value) => {
            if (this.status === PENDING) {
                this.status = FULFILLED;
                this.value = value;
                // 发布
                this.onResolvedCallbacks.forEach(fn => fn());
            }
        }

        const reject = (reason) => {
            if (this.status === PENDING) {
                this.status = REJECTED;
                this.reason = reason;
                // 发布
                this.onRejectedCallbacks.forEach(fn => fn());
            }
        }
        try {
            executor(resolve, reject);
        } catch (e) {
            reject(e);
        }
    }
    then(onFulfilled, onRejected) {
        // then调用后，返回一个新promise
        let promise2 = new Promise((resolve, reject) => {
            // 直接成功或失败
            if (this.status === FULFILLED) {
                try {
                    let x = onFulfilled(this.value);
                    // x有可能是promise，如果是promise需要看下这个promise是成功还是失败，成功则把成功的结果调用promise2的resolve传递进去。
                    // 总结：x的值决定是调用promise2的resolve还是reject，如果是promise则取他的状态，如果是普通值，则直接调用resolve；
                    resolve(x);
                } catch (e) {
                    reject(e);
                }
            }
            if (this.status === REJECTED) {
                try {
                    let x = onRejected(this.reason);
                    resolve(x);
                } catch (e) {
                    reject(e);
                }
            }
            // 有定时器的情形，先保存起来，resolve的时候依次调用（订阅）
            if (this.status === PENDING) {
                this.onResolvedCallbacks.push(() => {
                    try {
                        let x = onFulfilled(this.value);
                        resolve(x);
                    } catch (e) {
                        reject(e);
                    }
                });
                this.onRejectedCallbacks.push(() => {
                    try {
                        let x = onRejected(this.reason);
                        resolve(x);
                    } catch (e) {
                        reject(e);
                    }
                });
            }
        })
        return promise2;
    }
}

module.exports = Promise;